﻿using System;
using System.Collections.Generic;
using Dict.DataModel;

namespace Battle.Engine.LogicModel
{
    //状态
    public enum FSkillState
    {
        None = 0,       //没被释放
        WAIT = 1,       //排队中
        DOING = 2,      //释放中
        LAST = 3,       //最后一个cast释放完
        FINISH = 4,     //技能结束
    }

    //mxd 技能是否需要派生
    public class FSkill
    {
        public FSkillState state;           //技能的状态,放过的就不能再放了
        public bool enable;                 //是否可用(可以通过外部的接口关闭技能)

        public string id;
        public int index;
        public bool IsUltimate = false;     //是否是大招
        public SkillClass skillClass;       //0为近战，1为远程
        public AttackType attackType;       //技能类型
        public double duration;             //技能总时间
        public int cooldownCur;             //当前的冷却状态
        public int cooldown;                //小招的冷却时间（2回合）大招的冷却时间（4回合）
        public int castSelectPointRule;     //展示的选取规则
        public List<FSkillCast> casts;      //技能里的出手顺序
        public List<FRelease> releases;     //射击+伤害事件列表

        public double stepBegin;            //内部数据,技能开始的回合时间
        public Queue<FRelease> stepReleases;  //内部数据,每个Release的执行时间
        public FRelease curStepRelease; //内部数据,记录在Step Release阶段,最早的Release是哪个
        public double stepEnd;              //内部数据,技能结束的回合时间
        public int stepState;               //内部数据,-1技能没释放的状态状态
        public bool isFirstCastStart;       //第一次cast是否已开始
        public double skipTime;             //跳过技能的时间

        public FActor target;               //选取的中心目标
        public List<FActor> sameDamTargets;        //受同等伤害的人
        public List<FActor> castTargets;        //保存每次cast的攻击范围
        public int needMove;                 //内部数据,是否有移动


        public FActor actor;                //技能所有者

        public void init(FActor actor, string id, int index, EngineData data)
        {
            this.actor = actor;
            this.id = id;
            this.index = index;

            this.state = FSkillState.None;
            this.enable = true;

            this.casts = new List<FSkillCast>();

            TableSkill tData = data.tableDataUtil.GetTableSkill(id);
            this.duration = tData.Duration;
            this.IsUltimate = (tData.IsUltimate > 0);
            this.cooldownCur = 0;
            if (this.IsUltimate)
            {//获取大招的冷却时间
                this.cooldown = data.tableDataUtil.GetUltimateSkillCoolDown();
            }
            else
            {//获取小招的冷却时间
                this.cooldown = data.tableDataUtil.GetNormalSkillCoolDown();
            }
            this.castSelectPointRule = tData.SkillCastPointSelectRule;
            List<TableSkillCast> castDatas = data.tableDataUtil.GetTableSkillCastBySkillId(id);
            //技能成长加成
            double skillDamAdd = tData.LevelGrowFactor * (this.actor.breachedLevel-1) * CommonMethod.tableAttributeConvert / castDatas.Count;
            foreach (var castData in castDatas)
            {
                //TODO 需要处理技能cast排序，保证第一个技能cast在前
                FSkillCast cast = new FSkillCast();
                cast.init(this, castData);
                cast.exportFactor += skillDamAdd; //处理突破的技能加成
                this.attackType = cast.exportType;
                AddAndSortCast(cast);
            }

            this.releases = new List<FRelease>();
            this.skillClass = (SkillClass)tData.SkillClass;
            //把cast拆成release，并且时间排序
            foreach (var cast in this.casts)
            {
                //是近战还是抛射物
                switch (this.skillClass)
                {
                    case SkillClass.IMMEDIATE:
                        {
                            FRelease release = new FRelease();
                            release.init(cast, true, cast.castData.CastTime);
                            AddAndSortRelease(release);
                        }
                        break;
                    case SkillClass.IMMEDIATE_PROJECT:
                        {
                            FRelease release1 = new FRelease();
                            release1.init(cast, false, cast.castData.CastTime);
                            AddAndSortRelease(release1);

                            FRelease release2 = new FRelease();
                            release2.init(cast, true, cast.castData.CastTime + cast.castData.FlyTime);
                            AddAndSortRelease(release2);
                        }
                        break;
                    default:
                        {
                            Debug.LogError("Unknow SkillClass!!");
                        }
                        break;
                }
            }
            //给最后一个Release标识一下
            if (this.releases.Count > 0)
            {
                FRelease release = this.releases[this.releases.Count - 1];
                release.isLast = true;
            }
            
            this.stepState = -1;
            this.stepReleases = new Queue<FRelease>();
            this.curStepRelease = null;
            this.skipTime = 0;
            this.isFirstCastStart = false;

            this.sameDamTargets = new List<FActor>();
            this.needMove = 0;
        }

        public void Wait(EngineData data)
        {
            this.state = FSkillState.WAIT;
        }

        //实际开始释放技能
        public void Do(EngineData data)
        {
            //选取目标 不能选择已死亡的人，不能选择隐身的人，可以选择无敌的人
            List<SelectLimitCondition> limitConditions = data.LimitConditions(false, false, true);
            if(this.attackType == AttackType.TREAT)
            {//治疗技能目标为己方
                this.target = data.range.GetFirstActor(this.actor.player.actors, null, limitConditions, data);
            }
            else
            {
                this.target = data.range.GetFirstActor(data.getPlayerByCampType(actor.player.enemyCamp).actors, null, limitConditions, data);
            }

            if (this.target == null)
            {//当前敌方已经没有人能被击
                return;
            }
            castTargets = data.SelectTargetActors(true, this.casts[0].selectStrategy, this.actor, this.target, limitConditions);
            this.target = castTargets[0];
            Debug.LogFightMsg("--------do skill: time=" + data.roundTime + ", id:" + this.id + "===>targetId:" + this.target.heroId + ",uniqueId:" + this.target.uniqueId);

            this.sameDamTargets.Clear();
            this.stepReleases.Clear();
            this.state = FSkillState.DOING;

            //计算技能释放时间点
            this.stepState = 0;
            this.curStepRelease = null;
            this.isFirstCastStart = false;
            double curtime = data.roundTime;
            if (this.IsUltimate)
            {
                this.needMove = 1;
                this.stepBegin = curtime;
                curtime  = curtime  + data.tableDataUtil.GetUltimateMoveToSkillTime();
                foreach (var release in this.releases)
                {
                    release.time = curtime + release.oritime;
                    this.stepReleases.Enqueue(release);
                }
                this.skipTime = curtime + this.duration;
                this.stepEnd = curtime + this.duration + data.tableDataUtil.GetUltimateEndCameraTime(); 
                this.actor.ResetPosition();
            }
            else
            {
                //距离近,直接攻击.距离远，需要先移动过去
                //如果目标就在身边并且攻击站位和上一次没有变化,或者是远程,直接开始攻击, 否则移动过去
                if ( (this.actor.curCastTargetPosition != null && this.actor.curCastTargetPosition == target.position && this.actor.curCastSelectPointRule == this.castSelectPointRule) ||
                    this.castSelectPointRule == (int)SkillCastSelectPointRule.Remote)
                {
                    this.needMove = 0;
                    this.stepBegin = curtime;
                    foreach (var release in this.releases)
                    {
                        release.time = this.stepBegin + release.oritime;
                        this.stepReleases.Enqueue(release);
                    }
                    this.stepEnd = this.stepBegin + this.duration;
                }
                else
                {
                    this.needMove = 1;
                    this.stepBegin = curtime;
                    curtime = curtime + data.tableDataUtil.GetNormalMoveToSkillTime(this.actor.heroClass);
                    foreach (var release in this.releases)
                    {
                        release.time = curtime + release.oritime;
                        this.stepReleases.Enqueue(release);
                    }
                    this.stepEnd = curtime + this.duration;
                    this.actor.curCastTargetPosition = target.position;
                    this.actor.curCastSelectPointRule = this.castSelectPointRule;
                }
            }
        }

        //mxd 是否需要返回技能结束的标志
        public void Update(EngineData data)
        {
            if (this.stepState == 0 && this.target != null)
            {
                UpdateSkillBegin(data);
            }

            if (this.stepState == 1)
            {
                UpdateSkillRelease(data);
            }

            if (this.stepState == 2)
            {
                UpdateSkillEnd(data);
            }
        }

        public void ResetRound(EngineData data)
        {
            this.state = FSkillState.None;
            this.target = null;

            foreach (var cast in this.casts)
            {
                cast.ResetRound(data);
            }
            this.stepBegin      = 0;
            this.stepReleases.Clear();
            this.stepEnd        = 0;
            this.stepState      = 0;
            this.curStepRelease = null;

            needMove = 0;
        }
        private void AddAndSortCast(FSkillCast cast)
        {
            for (int i = 0; i < this.casts.Count; ++i)
            {
                FSkillCast obj = this.casts[i];
                if (Int32.Parse(obj.id) > Int32.Parse(cast.id))
                {
                    this.casts.Insert(i, cast);
                    return;
                }
            }
            this.casts.Add(cast);
        }
        private void AddAndSortRelease(FRelease release)
        {
            for (int i = 0; i < releases.Count; ++ i)
            {
                FRelease obj = releases[i];
                if (obj.oritime > release.oritime)
                {
                    this.releases.Insert(i, release);
                    return;
                }
            }
            this.releases.Add(release);
        }

        private void UpdateSkillBegin(EngineData data)
        {
            if (data.roundTime >= this.stepBegin)
            {
                //移动到目标点
                if (this.actor.curCastTargetPosition != null)
                    this.actor.position = this.actor.curCastTargetPosition;
                data.compute.SkillBegin(this, castTargets);

                ++ this.stepState;
            }
        }
        
        private void UpdateSkillRelease(EngineData data)
        {
            for (int i = 0; i < 100; ++ i)
            {
                if (this.stepReleases.Count == 0 && this.curStepRelease == null)
                {
                    ++this.stepState;
                    return;
                }

                if (this.curStepRelease == null)
                {
                    this.curStepRelease = this.stepReleases.Dequeue();
                }

                if (data.roundTime >= this.curStepRelease.time)
                {
                    //释放Release
                    this.curStepRelease.Do(data);

                    this.curStepRelease = null;
                    if(this.state == FSkillState.FINISH)
                    {
                        this.stepState = -1;
                        return;
                    }
                    if (this.stepReleases.Count == 0)
                    {
                        this.state = FSkillState.LAST;
                        ++this.stepState;
                        return;
                    }
                }
                else
                {
                    break;
                }
            }
        }

        private void UpdateSkillEnd(EngineData data)
        {
            if (data.roundTime >= this.stepEnd)
            {
                ++this.stepState;
                this.stepState = -1;        //设置状态为技能结束
                this.state = FSkillState.FINISH;

                this.actor.SkillEnd(data);  //通知actor技能结束
                this.actor.player.SkillEnd(this);
                data.compute.SkillEnd(this.actor.player.camp, this.actor.uniqueId, this);
            }
        }
    }
}
